require 'socket'
require 'library'
require 'makehash'

module  Data_Base_Manager

public

#creates the server	
	def Data_Base_Manager.server()
		server = nil
		i = 34567
		while(server == nil)
			server = TCPServer.new('127.0.0.1',i)
			i = i + 3
		end
		port = open("port.config","w")
		port.write(i)
		port.close
		configure()
		listen(server) 
	end

# everything need to keep the server going 

private
	

#gets the infomation out of the request string
#request form is 	set <pluginID> <filepath> <artist> <album> <title> <duration> <hash> <playcount> <rating> <last_played>
#request form is 	get <file_name>
#send form is 		<filepath> <artist> <album> <title> <duration> <hash> <playcount> <rating> <last_played>
#request form is 	marco or marco <pluginID>
#send form is 		polo or polo <pluginID> 
#request form is 	new <pluginID> <location> <artist> <album> <title> <duration> <play_count> <rating> <last_played>
#send form is 		conflict  <play_count> <rating> <last_played>
#request form is 	startup <pluginID>
#request form is 	change <location>
#request form is 	ftp get

#send form is 		<time_interval_update> <time_of_last_update> <local_lib_loc> <local_lib_name> <remote_login_pw> <remote_login_name> <remote_loc> <remote_dir> <remote_name>
# this is in the form of a array to_s

#request form is ftp set <time_interval_update or -> <time_of_last_update or -> <local_lib_loc or -> <local_lib_name or -> <remote_login_pw or -> <remote_login_name or -> <remote_loc or -> <remote_dir or -> <remote_name or ->

#send form  <time_interval_update> <time_of_last_update> <local_lib_loc> <local_lib_name> <remote_login_pw> <remote_login_name> <remote_loc> <remote_dir> <remote_name>
# this is also in the form of a array to_s

# request form is 	ftp to
# request form is 	ftp from
	def parse_request(request,session)
		broken = request.scan(/\w+/)

#used to update the lib
	        if broken[0] == "set" then  
			lib = Library.new(@database_loc)
			change = Song.new(broken[2],broken[3],broken[4],broken[5],broken[6],broken[7],broken[8],broken[9],broken[10])
			lib.update_song(change) 
			lib.save(@database_loc)
			doc_change(broken[1],change) 
			session.send("\"OK\"")
#used for players without a library
		if broken[0] == "increment" then
			lib = Library.new(@database_loc)
			change = Song.new(broken[1],nil,nil,nil,nil,nil,nil,nil,nil)
			lib_song = lib.get_song(change.hash)
			lib_song.play_count = lib_song.play_count + 1
			lib.update_song(lib_song) 
			lib.save(@database_loc)
			doc_change(broken[1],lib_song) 
			session.send("\"OK\"")
		
#used to make a connect between plugin and server
		elsif  broken[0] == "marco" then
			if broken.length == 1 then 
				pluginID = getid()
				config = File.new("server.config",APPEND)
				output = String.new("#{pluginID}\n")
				config.write(output)
				config.close
				configure()
				output = String.new("")
				output << "polo" << " " << pluginID
				if !session.send(output) then
					print "ERROR: failed to send to plugin\n"
				end
		 	else
				if !session.send("polo") then
					print "ERROR: failed to send to plugin\n"
				end
			end
		elsif broken[0] == "version" then 
			session.send("#{@server_version}")
#for all the new players out there
		elsif broken[0] == "get" then
			lib = Library.new(@database_loc)
			change = Song.new(broken[2],nil,nil,nil,nil,nil,nil,nil,nil,nil)
			lib_song = Library.get_song(change.hash)
			session.send(lib_song.to_response)
		elsif broken[0] == "new" then 
			lib = Library.new(@database_loc)
			change = Song.new(broken[2],broken[3],broken[4],broken[5],broken[6],broken[7],broken[8],broken[9],broken[10])
			lib_song = Library.get_song(change.hash)	
			if(change.rating - lib_song.rating != 0) or (lib_song.rating == 0) then 
				message = String.new("conflict")
#plugin must know the song that it is dealing with
				message << " "<< lib_song.rating << " " << lib_song.play_count << " " << lib_song.last_played 
				session.send(message)
			else 
				session.send("\"OK\"")
			end
			
#for all the old players out there
		elsif broken[0] == "startup" then
			f = File.new(broken[1],"r")
			list = f.readlines
			changes_since_last_load(broken[1],list,session)
			f.close
	   	elsif broken[0] == "ftp" then
			ftp = Ftp_File_Mananger.new()
			if broken[1] == "set" then
				i = 0
				a = Array.new(broken.length - 2)
				while(i+2 < broken.length) 
					a[i] = broken[i+2]
					i = i+1	
				end
				ftp.ftp_configure(a)
				a = ftp.get_all
				session.send(a.to_s)
			elsif broken[1] == "get" then
				s = ftp.get_all
				session.send(a.to_s)
#			elsif broken[1] == "to" then
#				ftp.ftp_startup(0)
			elsif broken[1] == "from" then
				ftp.ftp_startup(1)
			else 
				print"not a command"
			end
#when the user wants to change the file for the lib					
		else
			print "ERROR: Bad request send to the server\n"
		end
	end
#configures settings
	def configure()
		config_file = File.new("server.config","r")
		configs = config_file.readlines
		@server_version = configs[0]
		@database_loc = configs[1] 
		i = 0
		@current_players = Array(configs.length-2)
		while (i < (configs.length - 2)) 
			 @current_players[i] = configs[i+2]
			i = i + 1
		end
		config_file.close
		i = 0
		while ( i < @current_players.length)
			infile = File.new(@current_players[i].to_s,CREAT|EXCL)
			if (infile != nil) then 
				infile.close
			end
		end
	end 
#this function takes care of the changes to the library since the last load
	def changes_since_last_load(pluginID,state,session)
		i = 0
	      	File.truncate(pluginID.to_s,0)
		lib = Library.new(@database_loc)
		message = String.new("")
		while(i < state.size) 
			message << "\"" << state[i] << "\""
			i = i+1
		end
		session.send(message)

	end
#listens for sessions forever
	def listen(server)
		threading = Array.new(2)
		threading[0] = "ftp_th"
		threading[1] = "dbm_th"
		threads = []
		timing = 0
			threads << thread.new(threading) { |my_th|
#		this is the ftp
			if my_th == "ftp_th" then
				ftp= Ftp_File_Mananger.new()
				if ftp.get_time == "-" then 
					timing = Time.now.to_i	
				end	
				while (1) 
					if Time.now.to_i >= timing+3600 then 
						ftp.init_ftp
						if ftp.get_time == "-" then 
							timing = Time.now.to_i	
						end	
					end
					if Time.now.to_i >= ftp.get_time + ftp.get_last_time then
						ftp.ftp_startup(0)
					end
				end
#		this is the databasemanager 
			else
				while (session = server.accept)
					message = String.new("")
					m = session.recv(256) 
					message << m 
					parse_request(message,session)
                        		session.close
                		end
			end
			}
		threads.each { |aThread|  aThread.join }
	end
#documents the change that has occur in the library
#saves the in the form of <hash> <rating> <playcount> <last_played>
	def doc_change(pluginID,s)
		i = 0 
		infile = 0
		output = String.new("#{s.hash}\n")
		whille (i < @current_players.length)
			if(@current_players[i] != pluginID) then
				infile = File.open(@current_players[i].to_s,APPEND)
				infile.write(output)
				infile.close
			end
			i = i+1
		end
	end 
#gives a plugin a new id that has not been used by another plugin
	def get_id() 
		number = 0
		while(1) 
			i = 0
			conflict = 0
			number = rand() % 4294967295
			while( i < @current_players.length)
				if number == @current_players[i] then 
					conflict = 1
					break
				end
			end
			if conflict == 0 then 
				break
			end
		end
		return number
	end
